summaryrefslogtreecommitdiff
path: root/src/frontend/pages/product/[productId]/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/pages/product/[productId]/index.tsx')
-rw-r--r--src/frontend/pages/product/[productId]/index.tsx107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/frontend/pages/product/[productId]/index.tsx b/src/frontend/pages/product/[productId]/index.tsx
new file mode 100644
index 0000000..15766c8
--- /dev/null
+++ b/src/frontend/pages/product/[productId]/index.tsx
@@ -0,0 +1,107 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+import { NextPage } from 'next';
+import Head from 'next/head';
+import Image from 'next/image';
+import { useRouter } from 'next/router';
+import { useCallback, useState, useEffect } from 'react';
+import { useQuery } from '@tanstack/react-query';
+import Ad from '../../../components/Ad';
+import Footer from '../../../components/Footer';
+import Layout from '../../../components/Layout';
+import ProductPrice from '../../../components/ProductPrice';
+import Recommendations from '../../../components/Recommendations';
+import Select from '../../../components/Select';
+import { CypressFields } from '../../../utils/enums/CypressFields';
+import ApiGateway from '../../../gateways/Api.gateway';
+import { Product } from '../../../protos/demo';
+import AdProvider from '../../../providers/Ad.provider';
+import { useCart } from '../../../providers/Cart.provider';
+import * as S from '../../../styles/ProductDetail.styled';
+import { useCurrency } from '../../../providers/Currency.provider';
+
+const quantityOptions = new Array(10).fill(0).map((_, i) => i + 1);
+
+const ProductDetail: NextPage = () => {
+ const { push, query } = useRouter();
+ const [quantity, setQuantity] = useState(1);
+ const {
+ addItem,
+ cart: { items },
+ } = useCart();
+ const { selectedCurrency } = useCurrency();
+ const productId = query.productId as string;
+
+ useEffect(() => {
+ setQuantity(1);
+ }, [productId]);
+
+ const {
+ data: {
+ name,
+ picture,
+ description,
+ priceUsd = { units: 0, currencyCode: 'USD', nanos: 0 },
+ categories,
+ } = {} as Product,
+ } = useQuery({
+ queryKey: ['product', productId, 'selectedCurrency', selectedCurrency],
+ queryFn: () => ApiGateway.getProduct(productId, selectedCurrency),
+ enabled: !!productId,
+ }
+ ) as { data: Product };
+
+ const onAddItem = useCallback(async () => {
+ await addItem({
+ productId,
+ quantity,
+ });
+ push('/cart');
+ }, [addItem, productId, quantity, push]);
+
+ return (
+ <AdProvider
+ productIds={[productId, ...items.map(({ productId }) => productId)]}
+ contextKeys={[...new Set(categories)]}
+ >
+ <Head>
+ <title>Otel Demo - Product</title>
+ </Head>
+ <Layout>
+ <S.ProductDetail data-cy={CypressFields.ProductDetail}>
+ <S.Container>
+ <S.Image $src={"/images/products/" + picture} data-cy={CypressFields.ProductPicture} />
+ <S.Details>
+ <S.Name data-cy={CypressFields.ProductName}>{name}</S.Name>
+ <S.Description data-cy={CypressFields.ProductDescription}>{description}</S.Description>
+ <S.ProductPrice>
+ <ProductPrice price={priceUsd} />
+ </S.ProductPrice>
+ <S.Text>Quantity</S.Text>
+ <Select
+ data-cy={CypressFields.ProductQuantity}
+ onChange={event => setQuantity(+event.target.value)}
+ value={quantity}
+ >
+ {quantityOptions.map(option => (
+ <option key={option} value={option}>
+ {option}
+ </option>
+ ))}
+ </Select>
+ <S.AddToCart data-cy={CypressFields.ProductAddToCart} onClick={onAddItem}>
+ <Image src="/icons/Cart.svg" height="15" width="15" alt="cart" /> Add To Cart
+ </S.AddToCart>
+ </S.Details>
+ </S.Container>
+ <Recommendations />
+ </S.ProductDetail>
+ <Ad />
+ <Footer />
+ </Layout>
+ </AdProvider>
+ );
+};
+
+export default ProductDetail;